package com.je.gateway.router.dispatcher;

import com.google.common.base.Strings;
import com.je.gateway.router.loader.SecuriryUrlResourceLoader;
import com.je.gateway.xml.ConfigResourceLoader;
import com.je.gateway.router.model.security.SecurityUrl;
import com.je.gateway.util.UrlMatcher;
import io.vertx.core.http.Cookie;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.impl.RoutingContextImpl;
import org.apache.servicecomb.transport.rest.vertx.RestBodyHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import java.util.Map;

/**
 * 用于安全校验，非法请求不能进入系统内部
 */
public class SecurityDispatcher extends GatewayAbstractRestDispatcher {

    private static final Logger logger = LoggerFactory.getLogger(SecurityDispatcher.class);

    /**
     * 认证token的Key
     */
    public static final String X_AUTH_TOKEN = "authorization";

    private SecurityUrl configurations = new SecurityUrl();

    private ConfigResourceLoader<SecurityUrl> xmlConfigResourceLoader = new SecuriryUrlResourceLoader();

    private UrlMatcher urlMatcher;

    public SecurityDispatcher() {
        loadConfigurations();
    }

    @Override
    public int getOrder() {
        return 2;
    }

    @Override
    public void init(Router router) {
        String pattern = configurations.getPath();
        router.routeWithRegex(pattern)
                .handler(this::onRequestStatic)
                .failureHandler(this::onFailure)
                .handler(this::preCheck)
                .handler(createBodyHandler())
                .handler(this::onRequest);
    }

    protected void preCheck(RoutingContext context) {
        boolean doFilter = true;
        String url = context.request().path();
        if (urlMatcher.matches(url)) {
            doFilter = false;
        }

        String token = null;
        if (context.request().getHeader(X_AUTH_TOKEN) != null) {
            //从请求头获取token
            token = context.request().getHeader(X_AUTH_TOKEN);
        } else if (context.request().getParam(X_AUTH_TOKEN) != null) {
            //从request获取token
            token = context.request().getParam(X_AUTH_TOKEN);
        } else if (context.request().getFormAttribute(X_AUTH_TOKEN) != null) {
            //从form attribute中获取token
            token = context.request().getFormAttribute(X_AUTH_TOKEN);
        } else {
            //从cookie中获取token
            Map<String, Cookie> cookieMap = context.cookieMap();
            for (Map.Entry<String, Cookie> eachMap : cookieMap.entrySet()) {
                Cookie cookie = eachMap.getValue();
                if (cookie.getName().equals(X_AUTH_TOKEN)) {
                    token = cookie.getValue();
                }
            }
        }

        if (token != null && token.equals("undefined")) {
            token = null;
        }

        if (doFilter && Strings.isNullOrEmpty(token)) {
            context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.FALSE);
            context.next();
            return;
        }

        context.request().headers().add("isOpen", doFilter ? "0" : "1");
        if (!Strings.isNullOrEmpty(token)) {
            context.request().headers().add(X_AUTH_TOKEN, token);
        }
        context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.TRUE);
        context.next();
    }

    protected void onRequest(RoutingContext context) {
        Boolean bypass = context.get(RestBodyHandler.BYPASS_BODY_HANDLER);
        if (Boolean.TRUE.equals(bypass)) {
            // clear flag
            context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.FALSE);
            context.next();
            return;
        } else {
            context.request().response().setStatusCode(HttpStatus.UNAUTHORIZED.value()).end("用户未登陆，请先登陆！");
        }
    }

    protected void onRequestStatic(RoutingContext context) {
        RoutingContextImpl routingContext = (RoutingContextImpl) context;
        logger.info("url..................." + routingContext.normalisedPath());
        String url = routingContext.normalisedPath();
        String[] staticAll = new String[]{".js", ".css", ".ico", ".png", ".jpg", ".eot", ".svg", ".ttf", ".woff", ".json",
                ".html", ".js", ".css", ".ico", ".png", ".jpg", ".gif", ".eot", ".svg", ".ttf", ".woff", ".json", ".txt", ".ico", ".mp4", ".gz"};
        for (String s : staticAll) {
            if (url.indexOf(s) >= 0) {
                context.request().response().setStatusCode(HttpStatus.FORBIDDEN.value()).end("静态资源");
                return;
            }
        }
        context.next();
    }

    @Override
    public boolean enabled() {
        return true;
    }

    private void loadConfigurations() {
        configurations = xmlConfigResourceLoader.load();
        urlMatcher = new UrlMatcher(configurations.getPatterns());
    }

}
